﻿#include "TlvCodeTask.h"
#include "stores/StoreFilePath.h"
#include "utils/Time/Time.h"
#include "components/CodeEditor/PyCodeEditor.h"

#include <QDebug>


TlvCodeTask::TlvCodeTask(QObject *parent)
    : ITask{parent}
    , m_process(new QProcess())
    , m_ipc(new APIBridgeCom())
{
    moveThread(m_process); // 需要移动到线程
    // moveThread(m_ipc);  // 不要移动到线程！
    m_ipc->open();

    // stdout 和 stderr 合并
    // m_process->setProcessChannelMode(QProcess::MergedChannels);

    connect(m_process, &QProcess::readyReadStandardOutput, this, [=](){
        QString output = m_process->readAllStandardOutput();
        emit hasLog(output);
    });

    connect(m_process, &QProcess::readyReadStandardError, this, [=](){
        QString output = m_process->readAllStandardError();
        emit errorOccurred(output);
    });

    connect(m_process, qOverload<int,QProcess::ExitStatus>(&QProcess::finished), this, [=](int exitCode, QProcess::ExitStatus status){
        Q_UNUSED(status);
        QString exitMsg = tr("Process finished with exit code %1\n").arg(exitCode);
        exitMsg += "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<\n\n\n";
        emit hasLog(exitMsg);
    });

    connect(m_process, &QProcess::errorOccurred, this, [=](QProcess::ProcessError err){
        Q_UNUSED(err);
        // QString errMsg = tr("Process error: %1 (%2)\n").arg(err).arg(m_process->errorString());
        emit errorOccurred(m_process->errorString());
    });

    connect(m_ipc, &APIBridgeCom::errorOccurred, this, [=](const QString& msg){
        emit errorOccurred(msg);
    });
}

TlvCodeTask::~TlvCodeTask()
{
    stop();
    m_ipc->close();
    m_ipc->deleteLater();
    m_process->deleteLater();
}

void TlvCodeTask::stop()
{
    if (m_process->state() != QProcess::NotRunning) {
        m_process->kill();
        m_process->terminate();
    }
    ITask::stop();
}

void TlvCodeTask::setCode(const QString &code)
{
    m_code = code;
}

void TlvCodeTask::setCodeType(CodeType type)
{
    m_codeType = type;
}

TlvCodeTask *TlvCodeTask::instance()
{
    static TlvCodeTask* inst = nullptr;
    if (!inst) {
        inst = new TlvCodeTask();
    }
    return inst;
}

void TlvCodeTask::startProcess(const QString &proc, const QStringList &args)
{
    QString log = proc;
    for (const QString& arg : args) {
        log += QString(" \"%1\"").arg(arg);
    }
    emit hasLog(log);
    emit hasLog(tr("Process started >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"));
    m_process->start(proc, args);
    m_process->waitForFinished(-1);  // 等待进程结束
}

void TlvCodeTask::runTask()
{
    if (!m_ipc->isOpen()) {
        m_ipc->open();
    }

    switch (m_codeType) {
    case CodeType::JavaScript:
        runJs();
        break;
    case CodeType::Python:
        runPython();
        break;
    default:
        break;
    }

}

void TlvCodeTask::runJs()
{
    QFile f(StoreFilePath::predefJsPath());
    if (!f.open(QIODevice::ReadOnly)) {
        emit errorOccurred(tr(""));
        return;
    }
    QString predef = f.readAll();
    f.close();

    QString real = m_code;  // 同步函数：
    real = real.replace("Sleep(",   "await Sleep(");
    real = real.replace("SendTlv(", "await SendTlv(");
    real = real.replace("SendIIC(", "await SendIIC(");
    real = real.replace("ShowMsg(", "await ShowMsg(");
    real = real.replace("SelectFile(", "await SelectFile(");
    real = real.replace("Toast.info(", "await Toast.info(");
    real = real.replace("Toast.warning(", "await Toast.warning(");
    real = real.replace("Toast.error(", "await Toast.error(");
    real = real.replace("Toast.success(", "await Toast.success(");
    real = real.replace("\n", "\n\t");  // 格式化

    QString full = predef.replace("/*USERDEF_SCRIPTS_INPUT*/", real);

    QString scriptPath = QString("%1/%2_%3.js").arg(StoreFilePath::cacheJsDir()).arg(m_ipc->serverName()).arg(Time::getTimeString2());
    f.setFileName(scriptPath);
    if (!f.open(QIODevice::WriteOnly)) {
        emit errorOccurred(tr(""));
        return;
    }
    f.write(full.toUtf8()); // 写入
    f.close();

    startProcess(StoreFilePath::nodejsPath(), QStringList() << scriptPath/* << "--color=always"*/);
}

void TlvCodeTask::runPython()
{
    QFile f(StoreFilePath::predefPyPath());
    if (!f.open(QIODevice::ReadOnly)) {
        emit errorOccurred(tr(""));
        return;
    }
    QString predef = f.readAll();
    f.close();

    QString real = PyCodeEditor::convertPython2Prints(m_code);

    QString full = predef + "\n" + real;

    QString scriptPath = QString("%1/%2_%3.py").arg(StoreFilePath::cachePyDir()).arg(m_ipc->serverName()).arg(Time::getTimeString2());

    f.setFileName(scriptPath);
    if (!f.open(QIODevice::WriteOnly)) {
        emit errorOccurred(tr(""));
        return;
    }
    f.write(full.toUtf8()); // 写入
    f.close();

    startProcess("python", QStringList() << scriptPath);
}
